<!--基础表格-->
<template>
    <div class="base-grid">
        <a-spin tip="加载中..." :spinning="loading">
            <vxe-grid
                @page-change="handlePageChange"
                :height="height"
                :data="dataList"
                :seq-config="seqConfig"
                ref='xGrid'
                v-bind="options"
                v-on="$listeners"
            >
                <!--------------   表格主体插槽 form/empty/pager/bottom/top/toolbar---------------------------->
                <template v-for="(item,index) in $slots" :slot="index">
                    <slot :name="index" v-if="index==='empty' && !loading">没有更多了</slot>
                    <slot :name="index" v-else></slot>
                </template>
                <!--    工具栏左侧按钮自定义插槽-->
                <template #toolbar_button>
                    <template v-if="showToolbarButton">
                        <div class="flex flex-l toolbar-btn">
                            <!--  前缀按钮-->
                            <slot name="toolbar_button_pre"></slot>
                            <!-- 默认按钮-->
                            <div class="erp-toolbar">
                                <a-button size="small" icon="plus" type="primary" v-if="showAddBtn" @click="add">
                                    新增
                                </a-button>
                                <a-button size="small" icon="save" type="primary" v-if="showSave" @click="save">
                                    保存
                                </a-button>
                                <a-button size="small" icon="delete" @click="removes" v-if="showDelBtn">删除</a-button>
                                <a-button size="small" icon="reload" @click="$emit('refresh')" v-if="showRefreshBtn">刷新
                                </a-button>
                                <a-dropdown v-if="moreToolbar&&moreToolbar.length>0">
                                    <a-menu slot="overlay" @click="handleMenuClick">
                                        <a-menu-item v-for="(item,index) in moreToolbar" :key="index">
                                            {{ item }}
                                        </a-menu-item>
                                    </a-menu>
                                    <a-button size="small">更多
                                        <a-icon type="down"/>
                                    </a-button>
                                </a-dropdown>
                            </div>
                            <!-- 后缀按钮-->
                            <slot name="toolbar_button_suf"></slot>
                        </div>
                    </template>
                </template>
                <!--    工具栏右侧工具自定义插槽-->
                <template #toolbar_tools>
                    <template v-if="showToolbarTools">
                        <slot name="toolbar_tools_pre">
                        </slot>
                        <div style="margin-right: 10px">
                            <!--            <vxe-input size="mini" style="width:160px;" type="search"  v-model="searchValue" placeholder="搜索内容" clearable @search-click="$emit('search', searchValue)"></vxe-input>-->
                            <a-input-search size="small" :allowClear="searchType===2" style="width:160px;"
                                            v-model="searchValue"
                                            placeholder="搜索内容" type="search"
                                            @keyup="searchEvent"
                                            @search="$emit('search', searchValue)"></a-input-search>
                        </div>
                    </template>
                </template>
                <!-------------------------    表格列插槽------------------------>
                <template #header="{column, columnIndex, $columnIndex, _columnIndex, $rowIndex}">
                    <slot name="header" v-bind="{column, columnIndex, $columnIndex, _columnIndex, $rowIndex}">
                        {{ column.title }}
                    </slot>
                </template>
                <!--    展开行自定义插槽-->
                <template #content="{row, rowIndex, $rowIndex, column}">
                    <slot name="content" v-bind="{row, rowIndex, $rowIndex, column}">
                        <span>展开插槽没有内容~</span>
                    </slot>
                </template>
                <!--    过滤器自定义插槽-->
                <template #filter="{$panel, column, columnIndex, $columnIndex}">
                    <slot name="filter" v-bind="{$panel , column, columnIndex, $columnIndex}">
                        <div style="padding: 5px">
                            <a-input size="small" v-for="(option, index) in column.filters" :key="index"
                                     v-model="option.data" @keyup.enter="$panel.confirmFilter()"
                                     @input="$panel.changeOption($event, !!option.data, option)"></a-input>
                        </div>
                    </slot>
                </template>
                <!--    单元格自定义插槽-->
                <template #default="{row, rowIndex, $rowIndex, column, columnIndex, $columnIndex, _columnIndex}">
                    <slot name="default"
                          v-bind="{row, rowIndex, $rowIndex, column, columnIndex, $columnIndex, _columnIndex}">
                        <!--                        可编辑日期moment类型需转换-->
                        <span v-if="column.type === 'ADatePicker'">{{
                                moment(row[column.property], 'YYYY-MM-dd')
                            }}</span>
                        <!--                        不可编辑日期结构处理（后端不处理）-->
                        <span
                            v-else-if="column.type === 'date'|| column.type === 'dateTime'">{{
                                (row[column.property] + '_' + column.type) | filterDate
                            }}</span>
                        <!--                           弹窗类型-->
                        <a-button type="link" v-else-if="column.type === 'alert'" @click="showAlert(row,column)">
                            {{ row[column.property] }}
                        </a-button>
                        <!--                            其他类型默认展示html类型自动解析-->
                        <span v-else v-html="row[column.property]"></span>
                    </slot>
                </template>
            </vxe-grid>
        </a-spin>
    </div>

</template>

<script>
import tableConfig from '@/assets/js/lib/vxeTable/tableConfig'
import XEUtils from 'xe-utils/methods'
import moment from 'moment'
import 'moment/locale/zh-cn'
import { Sortable } from 'sortablejs'

export default {
    name: 'BaseGrid',
    data () {
        return {
            moment,
            sortable1: null,
            searchValue: '',
            baseConfig: {},
            originData: null,
            datasTmp: null,
            editType: {
                AInput: {
                    name: 'AInput',
                    props: {
                        allowClear: true,
                        readOnly: false
                    },
                    events: {
                        // pressEnter: this.inputSearch
                    }
                },
                AInputSearch: {
                    name: 'cusInputSearch',
                    props: {
                        allowClear: false,
                        enterButton: true
                    },
                    events: {
                        search: this.inputSearch
                        // pressEnter: this.inputSearch
                    }
                },
                ASelect: {
                    name: 'ASelect',
                    props: {
                        allowClear: false
                    }
                },
                ADatePicker: {
                    name: 'ADatePicker',
                    props: {
                        // allowClear: false
                        type: 'date'
                    },
                    events: {
                        openChange: this.openChange,
                        panelChange: this.panelChange
                    }
                }
            }
        }
    },
    props: {
        // 加载状态
        loading: {
            type: Boolean,
            default: false
        },
        // 表格高度
        padding: {
            type: [String],
            default: '5px'
        },
        height: {
            type: [String, Number],
            default: 'auto'
        },
        // 更多工具
        moreToolbar: {
            type: [Array, Boolean],
            default: () => {
                return ['导出']
            }
        },
        // 要合并的字段
        rowSpanFields: {
            type: [Array],
            default: () => {
                return []
            }
        },
        // 是否展示右侧工具栏
        showToolbarTools: {
            type: Boolean,
            default: true
        },
        // 是否展示左侧按钮
        showToolbarButton: {
            type: Boolean,
            default: true
        },
        // 是否展示保存按钮
        showSave: [Boolean],
        // 是否展示添加按钮
        showAddBtn: [Boolean],
        // 是否展示删除按钮
        showDelBtn: [Boolean],
        // 是否展示刷新按钮
        showRefreshBtn: [Boolean],
        // 是否展示搜索框
        showSearch: {
            type: Boolean,
            default: true
        },
        // 表尾合计事件
        foot: {
            type: Object,
            default: () => {
                return {}
            }
        },
        // 过滤器事件
        filterMethod: {
            type: Function,
            default: ({ row, column, options }) => {
                return row[column.property].toString().indexOf(options[0].data) >= 0
            }
        },
        // 展开事件
        expandLoadMethod: {
            type: Function,
            default: () => {
                return new Promise(resolve => {
                    resolve()
                })
            }
        },
        // 树节点展开事件
        treeLoadMethod: {
            type: Function,
            default: () => {
                return new Promise(resolve => {
                    resolve()
                })
            }
        },
        // 数据源
        datas: {
            type: Array,
            default: () => {
                return []
            }
        },
        // 列配置项
        columns: {
            type: Array,
            default: () => {
                return []
            }
        },
        // 是否展示toobar
        showToolbar: {
            type: Boolean,
            default: true
        },
        // 是否开启过滤器
        filterAble: {
            type: Boolean,
            default: true
        },
        // 第一列展示的类型 type：CheckBox/radio
        checkType: {
            type: String,
            default: ''
        },
        // 是否展示序号
        showSeq: {
            type: Boolean,
            default: false
        },
        // 搜索框默认值
        defaultSearchValue: {
            type: String,
            default: ''
        },
        // 搜索框类型 1.本地 2.远程
        searchType: {
            type: Number,
            default: 2
        },
        // 是否可以拖动列
        columnDrop: {
            type: Boolean,
            default: false
        }
    },
    created () {
        // 加载默认配置项
        this.baseConfig = tableConfig(this)
        if (this.columnDrop) {
            this.columnDrop1()
        }
    },
    beforeDestroy () {
        if (this.sortable1) {
            this.sortable1.destroy()
        }
    },
    mounted () {
        window.sWin = this._sWin
        this.$emit('setGrid', this.$refs.xGrid)
    },
    filters: {
        filterDate (value) {
            // const dateTime = '2017-12-31T23：59：59Z'
            const isUTC = value.substring(10, 11)
            if (isUTC !== 'T') {
                return value.substring(0, value.indexOf('_'))
            }
            const tmp = value.split('_')
            let res = ''
            if (tmp[1] === 'date') {
                res = tmp[0].substr(0, 10)
            } else if (tmp[1] === 'dateTime') {
                res = tmp[0].replace('T', ' ')
            }
            return res
        }
    },
    computed: {
        seqConfig () {
            try {
                return { startIndex: (this.$attrs.pagerConfig.currentPage - 1) * this.$attrs.pagerConfig.pageSize }
            } catch {
                return {}
            }
        },
        fields () {
            const arr = []
            this.columns && this.columns.forEach(item => {
                if (item.field) {
                    arr.push(item.field)
                }
            })
            return arr
        },
        dataList () {
            if (this.datasTmp && this.columns) {
                const list = this.datasTmp
                const field = this?.columns?.find(item => {
                    return item?.type === 'ADatePicker'
                })?.field
                // 将可编辑日期类型的时间进行moment化
                if (field) {
                    const listTmp = list.map(item => {
                        if (item[field]) {
                            item[field] = moment(item[field])
                        }
                        return { ...item }
                    })
                    return listTmp
                } else {
                    return this.datasTmp
                }
            } else {
                return []
            }
        },
        options () {
            if (this.columns && this.datasTmp) {
                const columns = this?.columns.map(item => {
                    if (item.type === 'number') {
                        item.formatter = this.formatters // 格式化
                    }
                    this.baseConfig.editRules[item.field] = item.rules
                    item.params = {
                        count: item.count
                    }
                    if (item.type === 'expand') { // 类型为扩展项增加扩展插槽
                        item.slots = { content: 'content' }
                    } else if (Object.keys(this.editType).includes(item.type)) { // 可编辑类型
                        item.editRender = {
                            autoselect: false,
                            immediate: false,
                            ...this.editType[item.type],
                            props: {
                                ...this.editType[item.type].props, // 各编辑组件特有的props默认值
                                size: 'small',
                                options: item?.options?.options, // 只对下拉选择框生效
                                ...item?.props // props项
                            }
                        }
                    } else if (item.type !== 'seq' && item.type !== 'html') { // seq html类型不加默认插槽，其他都加
                        item.slots = { default: 'default', ...item.slots }
                    }
                    item = { ...item, filters: item.filterable ? [{ data: '' }] : '' } // 动态处理是否展示过滤器
                    item.slots = Object.assign({}, { ...this.baseConfig.columns.slots, ...item.slots })
                    return { ...this.baseConfig.columns, ...item }
                })
                // 排序
                if (this.showSeq) {
                    columns.unshift({
                        type: 'seq',
                        title: '#',
                        width: 50
                    })
                }
                // 单选/多选
                if (this.checkType) {
                    columns.unshift({
                        type: this.checkType,
                        width: 50
                    })
                }

                // todo 以下优先级顺序为 接口配置>本地配置>默认配置
                const colConfig = {
                    ...this.baseConfig,
                    // ...this.gridOptions,
                    columns,
                    // pagerConfig: {
                    //     ...this.baseConfig.pagerConfig,
                    //     ...this.pagerConfig,
                    //     ...this.gridOptions.pagerConfig
                    // },
                    // toolbar: {
                    //     ...this.baseConfig.toolbar,
                    //     ...this.toolbar,
                    //     ...this.gridOptions.toolbar
                    // },
                    // 自定义列配置
                    customConfig: {
                        storage: {
                            resizable: !!this.$attrs.id
                        }
                    },
                    ...this.$attrs,
                    pagerConfig: {
                        ...this.baseConfig.pagerConfig,
                        ...this.$attrs.pagerConfig
                    }
                }
                console.log(colConfig)
                return colConfig
            } else {
                return { ...this.baseConfig, columns: [], ...this.$attrs }
            }
        }
    },
    watch: {
        defaultSearchValue: {
            handler (e) {
                this.searchValue = e
            },
            immediate: true
        },
        datas: {
            handler () {
                this.datasTmp = this.datas
                this.originData = this.datas
            },
            deep: true,
            immediate: true
        }
    },
    methods: {
        // 内置html跳转方法
        _sWin (url) {
            if (navigator.userAgent.indexOf('DingTalk') > 0 && self.frameElement && self.frameElement.tagName === 'IFRAME') {
                parent.window.iframecallback('add_tab', {
                    url: url,
                    callback: function (e) {
                        parent.window.iframe_load(e, true)
                    }
                })
            } else {
                window.open(`../../${url}`, '_blank')
            }
        },
        // 特殊格式日期格式化
        _formatDate (arr, field) {
            if (field) {
                const newArr = JSON.parse(JSON.stringify(arr)).map(item => {
                    return { ...item, [field]: moment(item[field]).format('YYYY/MM/DD') }
                })
                return newArr
            } else {
                return JSON.parse(JSON.stringify(arr))
            }
        },
        /**
         * 新增数据
         * @param defaultValue 新增时的默认值
         */
        add (defaultValue) {
            const xTree = this.$refs.xGrid
            const newRow = {}
            this.options.columns.forEach(item => {
                if (item.type === 'ADatePicker') {
                    newRow[item.field] = moment(this.dataList[item.field])
                } else {
                    newRow[item.field] = ''
                }
            })
            xTree.insertAt(newRow, -1)
        },
        // 保存数据
        save () {
            const field = this?.columns?.find(item => {
                return item?.type === 'ADatePicker'
            })?.field
            const { insertRecords, updateRecords } = this.$refs.xGrid.getRecordset()
            const removeRecords = this.$refs.xGrid.getRemoveRecords()
            const insertRecord = this._formatDate(insertRecords, field)
            const updateRecord = this._formatDate(updateRecords, field)
            const removeRecord = this._formatDate(removeRecords, field)
            this.$emit('save', { insertRecord, updateRecord, removeRecord })
        },
        openChange () {
        },
        panelChange () {
        },
        showAlert (row, column) {
            this.$emit('showAlert', { row, column })
        },
        // 搜索事件
        inputSearch (e, v) {
            this.$emit('inputSearch', { ...e, value: v })
        },
        // 更多工具点击事件
        handleMenuClick (e) {
            const name = this.moreToolbar[e.key]
            if (['导出'].includes(name)) {
                this.$refs.xGrid.openExport({ types: ['xlsx'] })
            }
            this.$emit('menuClick', { name: this.moreToolbar[e.key] })
        },
        // 表尾合计
        footerMethod ({ columns, data }) {
            // 通过接口配置，动态传递列字段及统计的值
            return [
                columns.map((column, columnIndex) => {
                    if (columnIndex === 0) {
                        return '合计'
                    } else if (Object.keys(this.foot).includes(column.property)) {
                        return this.foot[column.property]
                    }
                    return null
                })
            ]
            // 通过后端列配置前端自动计算
            // return [
            //     columns.map((column, columnIndex) => {
            //         if (columnIndex === 0) {
            //             return '合计'
            //         }
            //         if (column?.params?.count) {
            //             return XEUtils.sum(data, column.property)
            //         }
            //         return null
            //     })
            // ]
        },
        // 分页
        handlePageChange ({ currentPage, pageSize }) {
            // 内部处理好分页展示逻辑，外部负责接收页面及每页条数
            // 当前页
            if (this.$attrs.pagerConfig.currentPage) {
                this.$attrs.pagerConfig.currentPage = currentPage
            } else {
                this.baseConfig.pagerConfig.currentPage = currentPage
            }
            // 每页多少条
            if (this.$attrs.pagerConfig.pageSize) {
                this.$attrs.pagerConfig.pageSize = pageSize
            } else {
                this.baseConfig.pagerConfig.pageSize = pageSize
            }
            this.$emit('handlePageChange', {
                currentPage,
                pageSize
            })
        },
        // 删除事件
        removes () {
            const check = this.$refs.xGrid.getCheckboxRecords()
            if (check.length > 0) {
                this.$XModal.confirm('您确定要删除该数据?').then(type => {
                    if (type === 'confirm') {
                        this.$emit('remove', check)
                    }
                })
            } else {
                this.$XModal.message({
                    message: '请至少选择一条数据',
                    status: 'warning'
                })
            }
        },
        // 校验规则
        validator ({ cellValue, rule, rules, row, rowIndex, column, columnIndex }) {
            console.log('validatorc', cellValue)
            return new Error(1)
        },
        // 常用行合并
        rowspanMethod ({ row, _rowIndex, column, visibleData }) {
            const fields = this.rowSpanFields
            const cellValue = XEUtils.get(row, column.property)
            if (cellValue && fields.includes(column.property)) {
                const prevRow = visibleData[_rowIndex - 1]
                let nextRow = visibleData[_rowIndex + 1]
                if (prevRow && XEUtils.get(prevRow, column.property) === cellValue) {
                    return { rowspan: 0, colspan: 0 }
                } else {
                    let countRowspan = 1
                    while (nextRow && XEUtils.get(nextRow, column.property) === cellValue) {
                        nextRow = visibleData[++countRowspan + _rowIndex]
                    }
                    if (countRowspan > 1) {
                        return { rowspan: countRowspan, colspan: 1 }
                    }
                }
            }
        },
        // 本地搜索
        localSearch () {
            const filterName = XEUtils.toString(this.searchValue).trim()
            if (filterName) {
                const options = { children: 'children' }
                const searchProps = this.fields
                this.datasTmp = XEUtils.searchTree(this.originData, item => searchProps.some(key => XEUtils.toString(item[key]).indexOf(filterName) > -1), options)
                // 搜索之后默认展开所有子节点
                setTimeout(() => {
                    this.$nextTick(() => {
                        this.$refs.xGrid.setAllTreeExpand(true)
                    })
                }, 100)
            } else {
                this.datasTmp = this.originData
            }
        },
        // 创建一个防反跳策略函数，调用频率间隔 500 毫秒
        searchEvent: XEUtils.debounce(function () {
            if (this.searchType === 1) {
                this.localSearch()
            }
        }, 500, { leading: false, trailing: true }),
        // 列冻结
        toggleFixedColumn (arr = [], type = 'left') {
            if (arr instanceof Array) {
                const xTable = this.$refs.xGrid
                arr.forEach(index => {
                    const column = xTable.getColumns(index)
                    column.fixed = column.fixed ? null : type
                    // 刷新列
                })
                xTable.refreshColumn()
            } else {
                console.log('只接收数组类型')
            }
        },
        // 导出excel
        exportMethod (e) {
            console.log(e)
        },
        // 列拖拽
        columnDrop1 () {
            this.$nextTick(() => {
                const xTable = this.$refs.xGrid
                this.sortable1 = Sortable.create(xTable.$el.querySelector('.body--wrapper>.vxe-table--header .vxe-header--row'), {
                    handle: '.vxe-header--column:not(.col--fixed)',
                    onEnd: ({ item, newIndex, oldIndex }) => {
                        const { fullColumn, tableColumn } = xTable.getTableColumn()
                        const targetThElem = item
                        const wrapperElem = targetThElem.parentNode
                        const newColumn = fullColumn[newIndex]
                        if (newColumn.fixed) {
                            // 错误的移动
                            if (newIndex > oldIndex) {
                                wrapperElem.insertBefore(targetThElem, wrapperElem.children[oldIndex])
                            } else {
                                wrapperElem.insertBefore(wrapperElem.children[oldIndex], targetThElem)
                            }
                            return this.$XModal.message({ message: '固定列不允许拖动！', status: 'error' })
                        }
                        // 转换真实索引
                        const oldColumnIndex = xTable.getColumnIndex(tableColumn[oldIndex])
                        const newColumnIndex = xTable.getColumnIndex(tableColumn[newIndex])
                        // 移动到目标列
                        const currRow = fullColumn.splice(oldColumnIndex, 1)[0]
                        fullColumn.splice(newColumnIndex, 0, currRow)
                        xTable.loadColumn(fullColumn)
                        this.$emit('sortableOnEnd', { oldColumnIndex, newColumnIndex, fullColumn })
                    }
                })
            })
        },
        // 全局格式化
        formatters ({ column, cellValue }) {
            if (column.own.digits) {
                return XEUtils.commafy(XEUtils.toNumber(cellValue))
            } else {
                return cellValue
            }
        }
    }
}
</script>

<style lang="less">
</style>
<style scoped lang="less">
.base-grid {
    background: white;
}

/deep/ .vxe-table:not(.is--empty).show--foot.scroll--x .vxe-table--body-wrapper {
    overflow-y: hidden !important;
}

/deep/ .vxe-table:not(.is--empty).show--foot.scroll--x .vxe-table--body-wrapper:hover {
    overflow-y: scroll !important;
}

/deep/ .vxe-table:not(.is--empty).show--foot.scroll--x .vxe-table--body-wrapper::-webkit-scrollbar {
    width: 9px;
}

/deep/ .vxe-table:not(.is--empty).show--foot.scroll--x .vxe-table--body-wrapper::-webkit-scrollbar-thumb {
    background: #e5e5e5;
}

/deep/ .vxe-table--footer-wrapper.body--wrapper::-webkit-scrollbar-thumb {
    background: #d4d4d4;
}

/deep/ table {
    td {
        height: 28px !important;
    }
}

/deep/ .vxe-body--expanded-cell {
    padding: 10px !important;
}

.erp-toolbar {
    button {
        margin: 0 3px;
    }
}

/deep/ .vxe-toolbar.is--perfect {
    border: none !important;
}

</style>
